﻿' Copyright (C) 2015 HTTPBuilder
'
' This program is free software: you can redistribute it and/or modify it under the +terms 
' of the GNU General Public License as published by the Free Software Foundation, either 
' version 3 of the License, or (at your option) any later version.

' This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
' without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
' See the GNU General Public License for more details.

' You should have received a copy of the GNU General Public License along with this program.
' If not, see http://www.gnu.org/licenses/. 

Imports System.Text
Imports HTTPBuilder.Extensability

''' <summary>
''' 
''' </summary>
''' <remarks></remarks>
Public NotInheritable Class JsonFormatter
    Implements IFormatter

#Region "Member variables"
    Private ReadOnly _walker As StringWalker
    Private ReadOnly _writer As New IndentWriter()
    Private ReadOnly _currentLine As New StringBuilder()
    Private _quoted As Boolean
#End Region

#Region "Constructor"
    ''' <summary>
    ''' Returns a new instance of the JsonFormatter.
    ''' </summary>
    ''' <param name="json">Json content.</param>
    ''' <remarks></remarks>
    Public Sub New(json As String)
        _walker = New StringWalker(json)
        ResetLine()
    End Sub
#End Region

#Region "Public methods"
    ''' <summary>
    ''' Resets the length of the current line buffer.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub ResetLine()
        _currentLine.Length = 0
    End Sub

    ''' <summary>
    ''' Returns the formatted output as Json.
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Format() As String Implements IFormatter.Format
        While MoveNextChar()
            If Me._quoted = False AndAlso Me.IsOpenBracket() Then
                Me.WriteCurrentLine()
                Me.AddCharToLine()
                Me.WriteCurrentLine()
                _writer.Indent()
            ElseIf Me._quoted = False AndAlso Me.IsCloseBracket() Then
                Me.WriteCurrentLine()
                _writer.Outdent()
                Me.AddCharToLine()
            ElseIf Me._quoted = False AndAlso Me.IsColon() Then
                Me.AddCharToLine()
                Me.WriteCurrentLine()
            Else
                AddCharToLine()
            End If
        End While
        Me.WriteCurrentLine()
        Return _writer.ToString()
    End Function

    ''' <summary>
    ''' Deterimnes if the current char is an apostrophe.
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function IsApostrophe() As Boolean
        Return Me._walker.CurrentChar = """"c AndAlso Me._walker.IsEscaped = False
    End Function

    ''' <summary>
    ''' Deterimnes if the current char is an open bracket { or [.
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function IsOpenBracket() As Boolean
        Return Me._walker.CurrentChar = "{"c OrElse Me._walker.CurrentChar = "["c
    End Function

    ''' <summary>
    ''' Deterimnes if the current char is a close bracket } or ].
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function IsCloseBracket() As Boolean
        Return Me._walker.CurrentChar = "}"c OrElse Me._walker.CurrentChar = "]"c
    End Function

    ''' <summary>
    ''' Deterimnes if the current char is a colon.
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function IsColon() As Boolean
        Return Me._walker.CurrentChar = ","c
    End Function
#End Region

#Region "Private methods"
    ''' <summary>
    ''' Moves to the next char.
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function MoveNextChar() As Boolean
        Dim success As Boolean = _walker.MoveNext()
        If Me.IsApostrophe() Then
            Me._quoted = Not _quoted
        End If
        Return success
    End Function

    ''' <summary>
    ''' Adds the char to the line.
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub AddCharToLine()
        Me._currentLine.Append(_walker.CurrentChar)
    End Sub

    ''' <summary>
    ''' Outputs the line to the writer.
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub WriteCurrentLine()
        Dim line As String = Me._currentLine.ToString().Trim()
        If line.Length > 0 Then
            _writer.WriteLine(line)
        End If
        Me.ResetLine()
    End Sub
#End Region
End Class
